/*
 * Copyright (c) 2011, 2014 Oracle and/or its affiliates.
 * All rights reserved. Use is subject to license terms.
 *
 * This file is available and licensed under the following license:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *  - Neither the name of Oracle nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package cn.ryanpenn.javafx.samples.javafxui;

import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Button;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.web.HTMLEditor;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.apache.commons.lang3.StringUtils;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FXMLExampleController {

    @FXML
    private TextField userNameField;
    @FXML
    private TextField passwordField;
    @FXML
    private Text actiontarget;

    @FXML
    protected void handleSubmitButtonAction(ActionEvent event) {

        if (StringUtils.isEmpty(userNameField.getText()) ||
                StringUtils.isEmpty(passwordField.getText())) {
            actiontarget.setText("UserName or Password is empty.");
            userNameField.requestFocus();
        } else {
            actiontarget.setText("Welcome!");
        }

        newStage();
    }

    /**
     * layout
     *
     * @ref http://www.javafxchina.net/blog/docs/tutorial3/
     * @ref http://www.oracle.com/technetwork/cn/articles/java/layoutfx-1536156-zhs.html
     */
    private void newStage() {
        Stage stage = new Stage();
        stage.initModality(Modality.APPLICATION_MODAL); // 模态窗口
        stage.initOwner(null);

        VBox rootLayout = new VBox();
        Scene secondaryScene = new Scene(rootLayout, 1200, 800);
        stage.setScene(secondaryScene);
        stage.setTitle("欢迎使用");

        {
            MenuBar menuBar = new MenuBar();
            // --- Menu File
            Menu menuFile = new Menu("File");

            final ImageView pic = new ImageView();
            final Label name = new Label();
            final Label binName = new Label();
            final Label description = new Label();
            int currentIndex = -1;
            CheckMenuItem titleView = createMenuItem("Title", name);
            CheckMenuItem binNameView = createMenuItem("Binomial name", binName);
            CheckMenuItem picView = createMenuItem("Picture", pic);
            CheckMenuItem descriptionView = createMenuItem("Description", description);
            binNameView.setSelected(false);
            picView.setSelected(false);
            menuFile.getItems().addAll(titleView, binNameView, picView, descriptionView);

            // --- Menu Edit
            Menu menuEdit = new Menu("Edit");
            // --- Menu View
            Menu menuView = new Menu("View");
            menuBar.getMenus().addAll(menuFile, menuEdit, menuView);

            rootLayout.getChildren().addAll(menuBar);
        }

        GridPane grid = new GridPane();
        grid.setPadding(new Insets(25, 25, 25, 25));
        rootLayout.getChildren().add(grid);

        // Button & Label
        {
            Button btn = new Button();
            btn.setText("欢迎使用");
            btn.setOnAction(e -> {
                System.out.println("欢迎使用");
            });

            //一个带文本和图标的Label
            Image image = AssetsUtils.getImage("search-label.png");
            Label label = new Label("Search", new ImageView(image));

            HBox hbox = new HBox();
            hbox.setSpacing(10);
            hbox.getChildren().add(label);
            hbox.getChildren().add(btn);

            grid.add(hbox, 0, 0);
        }

        // RadioButton
        {
            final ToggleGroup group = new ToggleGroup();

            RadioButton rb1 = new RadioButton("Home");
            rb1.setToggleGroup(group);
            rb1.setUserData("Home");

            RadioButton rb2 = new RadioButton("Calendar");
            rb2.setToggleGroup(group);
            rb2.setUserData("Calendar");

            RadioButton rb3 = new RadioButton("Contacts");
            rb3.setToggleGroup(group);
            rb3.setUserData("Contacts");

            final ImageView icon = new ImageView();
            group.selectedToggleProperty().addListener(
                    (ObservableValue<? extends Toggle> ov, Toggle old_toggle,
                     Toggle new_toggle) -> {
                        if (group.getSelectedToggle() != null) {
                            final Image image = AssetsUtils.getImage(group.getSelectedToggle().getUserData().toString()
                                    + ".jpg");
                            icon.setImage(image);
                        }
                    });
            group.selectToggle(rb1);

            HBox hbox = new HBox();
            VBox vbox = new VBox();

            vbox.getChildren().add(rb1);
            vbox.getChildren().add(rb2);
            vbox.getChildren().add(rb3);
            vbox.setSpacing(10);

            hbox.getChildren().add(vbox);
            hbox.getChildren().add(icon);
            hbox.setSpacing(50);
            hbox.setPadding(new Insets(20, 10, 10, 20));

            grid.add(hbox, 1, 0);
        }

        // toggle
        {
            Rectangle rect = new Rectangle();
            rect.setWidth(200);
            rect.setHeight(50);
            rect.setFill(Color.WHITE);
            rect.setStroke(Color.DARKGRAY);
            rect.setStrokeWidth(2);
            rect.setArcHeight(10);
            rect.setArcWidth(10);

            final ToggleGroup group = new ToggleGroup();

            group.selectedToggleProperty().addListener(
                    (ObservableValue<? extends Toggle> ov, Toggle toggle, Toggle new_toggle) -> {
                        if (new_toggle == null) {
                            rect.setFill(Color.WHITE);
                        } else {
                            rect.setFill((Color) group.getSelectedToggle().getUserData());
                        }
                    });

            ToggleButton tb1 = new ToggleButton("Minor");
            tb1.setToggleGroup(group);
            tb1.setUserData(Color.LIGHTGREEN);
            tb1.setSelected(true);

            ToggleButton tb2 = new ToggleButton("Major");
            tb2.setToggleGroup(group);
            tb2.setUserData(Color.LIGHTBLUE);

            ToggleButton tb3 = new ToggleButton("Critical");
            tb3.setToggleGroup(group);
            tb3.setUserData(Color.SALMON);

            HBox hbox = new HBox();
            hbox.getChildren().addAll(tb1, tb2, tb3);

            VBox vbox = new VBox();
            vbox.getChildren().add(new Label("Priority:"));
            vbox.getChildren().add(hbox);
            vbox.getChildren().add(rect);
            vbox.setPadding(new Insets(20, 10, 10, 20));

            grid.add(vbox, 2, 0);
        }

        // treeTableView
        {
            List<Employee> employees = Arrays.<Employee>asList(
                    new Employee("Ethan Williams", "ethan.williams@example.com"),
                    new Employee("Emma Jones", "emma.jones@example.com"),
                    new Employee("Michael Brown", "michael.brown@example.com"),
                    new Employee("Anna Black", "anna.black@example.com"),
                    new Employee("Rodger York", "roger.york@example.com"),
                    new Employee("Susan Collins", "susan.collins@example.com"));

            TreeTableColumn<Employee, String> empColumn = new TreeTableColumn<>("Employee");
            empColumn.setPrefWidth(150);
            empColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<Employee, String> param) ->
                    new ReadOnlyStringWrapper(param.getValue().getValue().getName())
            );

            TreeTableColumn<Employee, String> emailColumn = new TreeTableColumn<>("Email");
            emailColumn.setPrefWidth(190);
            emailColumn.setCellValueFactory((TreeTableColumn.CellDataFeatures<Employee, String> param) ->
                    new ReadOnlyStringWrapper(param.getValue().getValue().getEmail())
            );

            final ImageView depIcon = new ImageView(AssetsUtils.getImage("department.png"));
            final TreeItem<Employee> root = new TreeItem<>(new Employee("Sales Department", ""), depIcon);
            root.setExpanded(true);
            employees.stream().forEach((employee) -> {
                root.getChildren().add(new TreeItem<>(employee));
            });

            TreeTableView<Employee> treeTableView = new TreeTableView<>(root);
            treeTableView.getColumns().setAll(empColumn, emailColumn);

            grid.add(treeTableView, 0, 1);
        }

        {
            final Slider slider = new Slider();
            slider.setMin(0);
            slider.setMax(50);

            final ProgressBar pb = new ProgressBar(0);
            final ProgressIndicator pi = new ProgressIndicator(0);

            slider.valueProperty().addListener((ObservableValue<? extends Number> ov, Number old_val, Number new_val) -> {
                pb.setProgress(new_val.doubleValue() / 50);
                pi.setProgress(new_val.doubleValue() / 50);
            });

            final HBox hb = new HBox();
            hb.setSpacing(5);
            hb.setAlignment(Pos.CENTER);
            hb.getChildren().addAll(slider, pb, pi);

            grid.add(hb, 0, 2);
        }

        {
            final FileChooser fileChooser = new FileChooser();

            final Button openButton = new Button("Open a Picture...");
            final Button openMultipleButton = new Button("Open Pictures...");

            openButton.setOnAction(
                    (final ActionEvent e) -> {
                        configureFileChooser(fileChooser);
                        File file = fileChooser.showOpenDialog(stage);
                        if (file != null) {
                            openFile(file);
                        }
                    });
            openMultipleButton.setOnAction(
                    (final ActionEvent e) -> {
                        configureFileChooser(fileChooser);
                        List<File> list = fileChooser.showOpenMultipleDialog(stage);
                        if (list != null) {
                            list.stream().forEach((file) -> {
                                openFile(file);
                            });
                        }
                    });

            final GridPane inputGridPane = new GridPane();

            GridPane.setConstraints(openButton, 0, 0);
            GridPane.setConstraints(openMultipleButton, 1, 0);
            inputGridPane.setHgap(6);
            inputGridPane.setVgap(6);
            inputGridPane.getChildren().addAll(openButton, openMultipleButton);

            final Pane rootGroup = new VBox(12);
            rootGroup.getChildren().addAll(inputGridPane);
            rootGroup.setPadding(new Insets(12, 12, 12, 12));

            grid.add(rootGroup, 1, 1);
        }

        {
            ObservableList<PieChart.Data> pieChartData
                    = FXCollections.observableArrayList(
                    new PieChart.Data("Grapefruit", 13),
                    new PieChart.Data("Oranges", 25),
                    new PieChart.Data("Plums", 10),
                    new PieChart.Data("Pears", 22),
                    new PieChart.Data("Apples", 30));

            final PieChart chart = new PieChart(pieChartData);
            chart.setTitle("Imported Fruits");

            final Label caption = new Label("");
            caption.setTextFill(Color.DARKORANGE);
            caption.setStyle("-fx-font: 24 arial;");
            chart.getData().stream().forEach((data) -> {
                data.getNode().addEventHandler(MouseEvent.MOUSE_PRESSED, (MouseEvent e) -> {
                    //caption.setTranslateX(e.getSceneX());
                    //caption.setTranslateY(e.getSceneY());
                    caption.setText(String.valueOf(data.getPieValue()) + "%");
                });
            });

            VBox vBox = new VBox();
            vBox.getChildren().addAll(chart, caption);

            grid.add(vBox, 2, 1);
        }

        {
            DropShadow ds = new DropShadow();
            ds.setOffsetY(3.0f);
            ds.setColor(Color.color(0.4f, 0.4f, 0.4f));

            Text t = new Text();
            t.setEffect(ds);
            t.setCache(true);
            t.setX(10.0f);
            t.setY(270.0f);
            t.setFill(Color.RED);
            t.setText("JavaFX drop shadow...");
            t.setFont(javafx.scene.text.Font.font(null, FontWeight.BOLD, 32));

            grid.add(t, 1, 2);
        }

        {
            final Tooltip tooltip = new Tooltip();
            tooltip.setText(
                    "\nYour password must be\n " +
                            "at least 8 characters in length\n"
            );
            Image image = AssetsUtils.getImage("icon.png");
            ImageView imgView = new ImageView(image);
            imgView.setFitWidth(30);
            imgView.setFitHeight(30);
            tooltip.setGraphic(imgView);

            Button btn = new Button();
            btn.setText("HtmlEditor");
            btn.setOnAction(e -> {
                newHtmlEditor(stage);
            });
            btn.setTooltip(tooltip);

            grid.add(btn, 2, 2);
        }

        stage.show();
    }

    //createMenuItem方法
    private CheckMenuItem createMenuItem(String title, final Node node) {
        CheckMenuItem cmi = new CheckMenuItem(title);
        cmi.setSelected(true);
        cmi.selectedProperty().addListener((ObservableValue<? extends Boolean> ov, Boolean old_val, Boolean new_val) -> {
            node.setVisible(new_val);
        });
        return cmi;
    }

    private void configureFileChooser(final FileChooser fileChooser) {
        fileChooser.setTitle("View Pictures");
        fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))
        );
    }

    private void openFile(File file) {
        EventQueue.invokeLater(() -> {
            try {
                Desktop.getDesktop().open(file);
            } catch (IOException ex) {
                Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
            }
        });
    }

    private void newHtmlEditor(javafx.stage.Window window) {
        Stage stage = new Stage();
        stage.initModality(Modality.APPLICATION_MODAL); // 模态窗口
        stage.initOwner(window);
        stage.setWidth(650);
        stage.setHeight(500);

        VBox root = new VBox();
        root.setPadding(new Insets(8, 8, 8, 8));
        root.setSpacing(5);
        root.setAlignment(Pos.BOTTOM_LEFT);

        final String INITIAL_TEXT = "<html><body>Lorem ipsum dolor sit "
                + "amet, consecteturadipiscingelit. Nam tortorfelis, pulvinar "
                + "in scelerisquecursus, pulvinar at ante. Nullaconsequat"
                + "conguelectus in sodales. Nullameuest a felisornare "
                + "bibendumetnectellus. Vivamus non metus tempus augueauctor "
                + "ornare. Duispulvinarjusto ac purusadipiscingpulvinar. "
                + "Integer conguefaucibusdapibus. Integer id nislutelit "
                + "aliquamsagittisgravidaeu dolor. Etiam sit ametipsum "
                + "sem.</body></html>";

        final HTMLEditor htmlEditor = new HTMLEditor();
        htmlEditor.setPrefHeight(245);
        htmlEditor.setHtmlText(INITIAL_TEXT);

        final TextArea htmlCode = new TextArea();
        htmlCode.setWrapText(true);

        ScrollPane scrollPane = new ScrollPane();
        scrollPane.getStyleClass().add("noborder-scroll-pane");
        scrollPane.setContent(htmlCode);
        scrollPane.setFitToWidth(true);
        scrollPane.setPrefHeight(180);

        Button showHTMLButton = new Button("Produce HTML Code");
        root.setAlignment(Pos.CENTER);
        showHTMLButton.setOnAction((ActionEvent arg0) -> {
            htmlCode.setText(htmlEditor.getHtmlText());
        });

        root.getChildren().addAll(htmlEditor, showHTMLButton, scrollPane);

        Scene scene = new Scene(new Group());
        scene.setRoot(root);
        stage.setScene(scene);
        stage.show();
    }

}
